﻿using System;
using System.IO;
using System.Threading;
using Useful.Sys;

namespace Useful.Document
{
    public class RemotePdfBatchPrinter : BasePdfBatchPrinter
    {
        private readonly string _host;
        private readonly string _remotePath;

        private const string shortMarkerFileName = "BullZipPdfWork.marker";
        private const int MAX_ATTEMPT = 30;
        private const int SLEEP_TIME = 1000;

        private FileStream fsMarkerFile;

        public RemotePdfBatchPrinter(string host, string remotePath, string gilyash)
            : base(gilyash)
        {
            this._host = host;
            this._remotePath = remotePath;

            LockPdfPrinter();

            Init();
        }

        private void LockPdfPrinter()
        {
            string fullMarkerFileName = GetLocalFileName(shortMarkerFileName, true);

            bool printerLocked = false;

            int appempt = 0;

            while (appempt < MAX_ATTEMPT && !printerLocked)
            {
                printerLocked = LockPdfPrinter(fullMarkerFileName);

                if (!printerLocked)
                    Thread.Sleep(SLEEP_TIME);

                appempt++;
            }

            if (!printerLocked)
                throw new Exception("Не получен эксклюзивный доступ к RemotePdfBatchPrinter");
        }

        private bool LockPdfPrinter(string fullMarkerFileName)
        {
            bool res = false;

            try
            {
                if (!File.Exists(fullMarkerFileName))
                {
                    fsMarkerFile = new FileStream(fullMarkerFileName, FileMode.CreateNew, FileAccess.Write, FileShare.None, 8, FileOptions.DeleteOnClose);

                    res = true; // Захватили принтер
                }
            }
            catch/*(Exception ex)*/
            {
            }

            return res;
        }

        private void UnLockPdfPrinter()
        {
            try
            {
                if (fsMarkerFile != null)
                    fsMarkerFile.Close();
            }
            catch/* (Exception ex)*/
            {
            }
        }

        protected override void CreateComObj()
        {
            Guid guidSettings = new Guid("F6C83BBD-F620-4F13-8320-9C51D1996EC4");
            PDFPrinterSettingsType = Type.GetTypeFromCLSID(guidSettings, _host);

            com_appPrinterSettings = Activator.CreateInstance(PDFPrinterSettingsType);

            Guid guidUtil = new Guid("F9444F96-C32A-4745-9FF3-9059B92CDAB0");
            PDFPrinterUtilType = Type.GetTypeFromCLSID(guidUtil, _host);

            com_appPrinterUtil = Activator.CreateInstance(PDFPrinterUtilType);
        }

        protected override string GetLocalFileName(string file, bool includeHostName)
        {
            string tmpFileName = Path.GetFileName(file);

            string tmpPath;

            if (includeHostName)
                tmpPath = SystemHelper.GetNetworkFullFileName(_host, _remotePath, tmpFileName);
            else
                tmpPath = Path.Combine(_remotePath, tmpFileName);

            return GetFileName(tmpPath);
        }

        public override void PrintFile(string file, string mergeFiles, string newName, bool protect, string ownerPassword)
        {
            base.PrintFile(file, mergeFiles, newName, protect, ownerPassword);

            CopyFileToUserComp(newName);
        }

        private void CopyFileToUserComp(string filename)
        {
            string tmpFileName = GetLocalFileName(filename, true);

            string srcFile = tmpFileName;
            string dstFileName = filename;

            try
            {
                File.Copy(srcFile, dstFileName, true);
            }
            catch (Exception ex)
            {
                throw new Exception("CopyFileToUserComp: " + ex.Message);
            }
        }

        public override void Dispose()
        {
            if (com_appPrinterUtil != null)
                System.Runtime.InteropServices.Marshal.ReleaseComObject(com_appPrinterUtil);

            if (com_appPrinterSettings != null)
                System.Runtime.InteropServices.Marshal.ReleaseComObject(com_appPrinterSettings);

            // Т.к. процессы ещё остаются в памяти некоторое время, то может здесь понадобится тайм-аут
            UnLockPdfPrinter();
        }
    }
}
